Skip to content

feat: ground naming and internals from a repo's conventional docs (itd-96)#126

Merged
REPPL merged 5 commits into
feat/itd-95-open-questions-adapterfrom
feat/itd-96-naming-internals-adapters
Jul 21, 2026
Merged

feat: ground naming and internals from a repo's conventional docs (itd-96)#126
REPPL merged 5 commits into
feat/itd-95-open-questions-adapterfrom
feat/itd-96-naming-internals-adapters

Conversation

@REPPL

@REPPL REPPL commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Grounds constraints/naming and internals at the conventions tier, from the files a team actually writes. Stacked on #124.

Resolves ledger issue iss-100 (.abcd/work/issues/open/) — this repository tracks issues in the record, not on GitHub, so there is no GitHub issue to auto-close.

Why

Both sections had exactly one adapter each, both native: nativeNamingSource reading the brief glossary, and the generic nativeBriefSource reading brief/05-internals/. A repository with a NAMING.md and an ARCHITECTURE.md sitting in plain sight still reported both blank, for want of an .abcd/ record. adr-36 makes that coverage debt, not a human-owned question.

What

convNamingSource reads a dedicated naming document first (NAMING.md, docs/naming*), and falls back to the glossary — cited with an explicit qualifier at lower confidence. A glossary defines terms rather than ruling on what may be renamed, so it is real evidence for naming but weaker evidence. glossary keeps its own adapter and its own row; naming is visibly a derived reading, never a duplicate. A test asserts the two rows differ in confidence and in cited string on a glossary-only fixture, and that exactly one adapter claims each section.

convInternalsSource combines architecture prose — measured with the existing README prose threshold rather than a new one — with a package-layout scan over WalkFiles.

Both ceiling at StatusPartial, matching what the mapping row already predicts for this tier, so signal strength lives in the confidence rather than in an inflated status. mapping.go is unchanged.

The security finding, and where it landed

Widening the tier gate to include the layout roots made a pre-existing hole in WalkFiles reachable: a tree carrying only src/ and no other conventional file now opens the conventions tier, and the walk had two unbounded dimensions.

  • Its cap counted regular files only — a tree of directories holding nothing regular never reaches it.
  • os.Root resolves every directory from the containment root one component at a time, so a chain of directories costs the square of its depth. A depth-1500 chain, trivial to create, did not finish in two minutes.

That is a denial of service on the operator's machine from an untrusted repository — exactly the population disembark targets, since abandoned wrecks often carry no README. The fix belongs with the primitive, so it landed on #124, not here: directories are counted against the same cap, descent is capped at maxWalkDepth, and both report through the existing truncated flag. Depth-1500 now walks in 0.4s; depth-400 went from 7.08s to 0.027s.

Rejected the reviewer's weaker alternative (dropping the layout roots from the tier gate) — spc-11 requires them, and removing them would falsely blank internals on a layout-only repo, which is an acceptance criterion.

Also fixed: a layout scan cut short by a cap no longer reads as a complete one. The truncation note was conditional on having found a package, so a walk that hit the cap before reaching a source root returned a blank asserting "no recognisable package layout" about a tree it never finished reading.

Verification

Detectors watched fail before each change, including the two walk-bound tests and the truncation-honesty tests. gofmt -l . empty, go build ./..., go vet ./..., go test ./..., go test -race ./internal/core/lifeboat/, abcd docs lint — all green. abcd intent ready itd-96 passes all four checks.

End-to-end against a record-less fixture repo (README, NAMING.md, ARCHITECTURE.md, an internal/ tree, work markers, no .abcd/):

constraints/naming      | partial | medium | conventions
    NAMING.md
evidence/open-questions | partial | low    | conventions
    4 work marker(s) across 2 file(s)
    internal/core/convert.go:3 (TODO)
    internal/core/convert.go:6 (FIXME)
    internal/store/store.go:3 (XXX)
    internal/store/store.go:4 (HACK)
internals               | partial | high   | conventions
    ARCHITECTURE.md
    cmd/wreck/
    internal/core/
    internal/store/
glossary                | blank
    searched GLOSSARY.md, docs/glossary* — still owned by convGlossarySource, no duplicate adapter

Every file in that tree hashed identically before and after the probe.

Captured, not fixed

iss-114os.Root path re-resolution is the quadratic underneath the depth cap; per-directory OpenRoot would make each open constant-time. Now bounded, so this is a performance follow-up rather than a hazard.

Two "consider" findings were left alone as spec-conformant design points: convDirHasMarkdown lists one level only, so a Diátaxis architecture tree whose Markdown lives in subdirectories is not recognised (matches the existing non-recursive convListADRs); and SourceContext has no walk cache, so the two whole-tree adapters walk independently.

REPPL added 5 commits July 21, 2026 17:38
The minted spc-11 stub carried no design record, so `abcd intent ready
itd-96` failed its spec_body check. Write the spec body, resolving every
one of itd-96's open questions: a dedicated naming document is naming's
primary source with the glossary as an explicitly-qualified fallback,
the preference order for architecture docs, the package-layout scan on
top of spc-10's WalkFiles, and the thresholds separating the confidence
levels.

Both new sections ceiling at partial, matching what the mapping row
already predicts for the conventions tier, so the strength of the signal
is carried by confidence rather than by inflating the status. That keeps
mapping.go — the brief-to-lifeboat contract — unedited.

impact: additive records the change class on the intent rather than in
CHANGELOG.md.

Assisted-by: Claude:claude-opus-4-8
constraints/naming and internals were each grounded by exactly one
adapter, both native, so a repository with a NAMING.md and an
ARCHITECTURE.md sitting in plain sight still reported both sections
blank for want of an .abcd/ record.

convNamingSource reads a dedicated naming document first and falls back
to the glossary, cited with an explicit qualifier at lower confidence: a
glossary defines terms rather than ruling on what may be renamed, so it
is real but weaker evidence. The glossary section keeps its own adapter
and its own row; naming is visibly a derived reading, never a duplicate.

convInternalsSource combines architecture prose, measured with the
README prose threshold, with a package-layout scan over WalkFiles. Both
sections ceiling at partial, matching what the mapping row already
predicts for this tier, so the strength of the signal lives in the
confidence rather than in an inflated status.

Also harden the walk itself, which the security review showed the tier
gate now makes reachable from a source tree carrying no other
conventional file. Its cap counted regular files only, so a tree of
directories holding nothing regular never reached it; and every
directory is resolved from the containment root one component at a time,
so a chain of directories costs the square of its depth. A depth-1500
tree took over two minutes and now takes 0.4s. Directories are counted
against the same cap and descent is capped at maxWalkDepth, both
reported through the existing truncated flag.

A layout scan cut short by a cap no longer reports as a complete one:
the truncation note is no longer conditional on having found a package,
and a blank drawn from a partial walk says the walk was partial.

Captured, not fixed: iss-113 (the marker adapter's truncation wording
names only the file cap), iss-114 (os.Root path re-resolution is the
quadratic underneath the depth cap).

Assisted-by: Claude:claude-opus-4-8
The bound-the-walk fix the security review forced belongs with the
WalkFiles primitive, so it landed on the parent branch. Merging it back
leaves this branch's diff as the itd-96 adapters alone.
The marker adapter's truncation evidence named only the file cap; it now
names all three bounds the walk enforces, fixed on the itd-95 branch
alongside the change that made the wording imprecise.

Assisted-by: Claude:claude-opus-4-8
Two decisions from the itd-95/itd-96 work that a future session would
otherwise re-litigate: that the mapping table's per-tier columns are a
ceiling adapters honour rather than a loose prediction, and that a walk
over a foreign tree must name which of entries, depth, and aggregate
bytes bounds it — a per-item cap and a count cap multiply, and their
product is not a bound.

Assisted-by: Claude:claude-opus-4-8
@REPPL
REPPL merged commit 66be7be into feat/itd-95-open-questions-adapter Jul 21, 2026
12 checks passed
@REPPL
REPPL deleted the feat/itd-96-naming-internals-adapters branch July 21, 2026 18:35
REPPL added a commit that referenced this pull request Jul 21, 2026
Both this programme and the derived-versioning programme minted spc-10
and spc-11 on the same day, from branches cut off the same base. abcd
mints the next free id from the local tree, so concurrent branches
always mint the same number and neither branch can see the collision.

It surfaces only on merge, and it breaks the bidirectional intent-spec
link in both directions at once: whichever spec wins the store lookup
leaves the other intent's link dangling, so `abcd intent ready` failed
for itd-95 and itd-67 simultaneously on the merged tree.

The derived-versioning programme's ids are already on main, so this
programme renumbers: spc-10 -> spc-12 (itd-95), spc-11 -> spc-13
(itd-96), with both intents' spec_id and every reference in the record
updated to match. The commit messages and PR bodies of #124 and #126
still name the old ids; that history is accurate as of when it was
written and is left alone.

Captured iss-115: specs need the uniqueness lint issues already have,
in record-lint so CI catches a collision on the PR rather than a human
catching it at merge.

Assisted-by: Claude:claude-opus-4-8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant